package edu.unlv.cs.ladders.web;

import java.util.Calendar;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.roo.addon.web.mvc.controller.RooWebScaffold;

import edu.unlv.cs.ladders.entities.Challenge;
import edu.unlv.cs.ladders.entities.Event;
import edu.unlv.cs.ladders.entities.Participant;
import edu.unlv.cs.ladders.entities.Score;
import edu.unlv.cs.ladders.entities.Team;
import edu.unlv.cs.ladders.entities.Tournament;
import edu.unlv.cs.ladders.notification.NotificationService;
import edu.unlv.cs.ladders.services.EventService;
import edu.unlv.cs.ladders.services.PermissionService;

import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;

@RooWebScaffold(path = "event", automaticallyMaintainView = false, formBackingObject = Event.class)
@RequestMapping("/event/**")
@Controller
public class EventController {
	@PreAuthorize("hasRole('ROLE_PARTICIPANT')")
    @RequestMapping(value = "/event", method = RequestMethod.POST)
    public String create(@Valid Event event, BindingResult result, ModelMap modelMap) {
        if (event == null) throw new IllegalArgumentException("A event is required");
        if (result.hasErrors()) {
            modelMap.addAttribute("event", event);
            modelMap.addAttribute("challenges", Challenge.findAllChallenges());
            modelMap.addAttribute("scores", Score.findAllScores());
            modelMap.addAttribute("teams", Team.findAllTeams());
            modelMap.addAttribute("tournaments", Tournament.findAllTournaments());
            modelMap.addAttribute("event_dateOfEvent_date_format", org.joda.time.format.DateTimeFormat.patternForStyle("S-", org.springframework.context.i18n.LocaleContextHolder.getLocale()));
            return "event/create";
        }
        /**
         * get the references to the objects that are already persisted.
         * this is so you do not get an error about needing to save transient objects.
         */
        event.setChallenger(Team.findTeam(event.getChallenger().getId()));
        event.setDefender(Team.findTeam(event.getDefender().getId()));
        event.setTournament(Tournament.findTournament(event.getTournament().getId()));
        
        event.persist();
        event.getDefender().addEvent(event);
        
        Score challengerScore = new Score();
        challengerScore.setEvent(event);
        challengerScore.setTeam(event.getChallenger());
        challengerScore.persist();
        event.setChallengerScore(challengerScore);
        
        Score defenderScore = new Score();
        defenderScore.setEvent(event);
        defenderScore.setTeam(event.getDefender());
        defenderScore.persist();
        event.setDefenderScore(defenderScore);

        Challenge challenge = new Challenge();
        challenge.setEvent(event);
        challenge.setNote(event.getNote());
        challenge.persist();
        event.addChallenge(challenge);
        
        this.getPermissionService().setDefaultPermissions(event);
        this.getPermissionService().setDefaultPermissions(challengerScore);
        this.getPermissionService().setDefaultPermissions(defenderScore);
        this.getPermissionService().setDefaultPermissions(challenge);
        
        this.getNotificationService().notifyTeamMembersOfNewEvent(event);
        return "redirect:/event/" + event.getId();
    }

	@PreAuthorize("hasRole('ROLE_PARTICIPANT')")
    @RequestMapping(value = "/event/defender/{defenderid}/form", method = RequestMethod.GET)
    public String createForm(@PathVariable("defenderid")Long defenderId,ModelMap modelMap) {
        Team defender = Team.findTeam(defenderId);
        Tournament tournament = defender.getTournament();
        Participant currentUser = Participant.getCurrentUser();
        Team challenger = tournament.findTeamWithMember(currentUser);
        
        Event event = new Event();
        event.setDefender(defender);
        event.setChallenger(challenger);
		event.setTournament(tournament);
        modelMap.addAttribute("event", event);
        modelMap.addAttribute("event_dateOfEvent_date_format", org.joda.time.format.DateTimeFormat.patternForStyle("S-", org.springframework.context.i18n.LocaleContextHolder.getLocale()));
        return "event/create";
    }
	
	@RequestMapping(value = "/event/{id}", method = RequestMethod.GET)
    public String show(@PathVariable("id") Long id, ModelMap modelMap) {
        if (id == null) throw new IllegalArgumentException("An Identifier is required");
        modelMap.addAttribute("event_dateOfEvent_date_format", org.joda.time.format.DateTimeFormat.patternForStyle("S-", org.springframework.context.i18n.LocaleContextHolder.getLocale()));
        modelMap.addAttribute("event", Event.findEvent(id));
        return "event/show";
    }
    
    @RequestMapping(value = "/event", method = RequestMethod.GET)
    public String list(@RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size, ModelMap modelMap) {
        if (page != null || size != null) {
            int sizeNo = size == null ? 10 : size.intValue();
            modelMap.addAttribute("events", Event.findEventEntries(page == null ? 0 : (page.intValue() - 1) * sizeNo, sizeNo));
            float nrOfPages = (float) Event.countEvents() / sizeNo;
            modelMap.addAttribute("maxPages", (int) ((nrOfPages > (int) nrOfPages || nrOfPages == 0.0) ? nrOfPages + 1 : nrOfPages));
        } else {
            modelMap.addAttribute("events", Event.findAllEvents());
        }
        modelMap.addAttribute("event_dateOfEvent_date_format", org.joda.time.format.DateTimeFormat.patternForStyle("S-", org.springframework.context.i18n.LocaleContextHolder.getLocale()));
        return "event/list";
    }
    
    @PreAuthorize("hasPermission(#event,'write') or hasRole('ROLE_COORDINATOR')")
    @RequestMapping(method = RequestMethod.PUT)
    public String update(@Valid Event event, BindingResult result, ModelMap modelMap) {
        if (event == null) throw new IllegalArgumentException("A event is required");
        if (result.hasErrors()) {
            modelMap.addAttribute("event", event);
            modelMap.addAttribute("event_dateOfEvent_date_format", org.joda.time.format.DateTimeFormat.patternForStyle("S-", org.springframework.context.i18n.LocaleContextHolder.getLocale()));
            return "event/update";
        }
        /**
         * Get the objects that are allowed to change
         */
        String note = event.getNote();
        Calendar dateOfEvent = event.getDateOfEvent();
        Integer challengerScoreValue = event.getChallengerScore().getScore();
        Integer defenderScoreValue = event.getDefenderScore().getScore();
        
        event = Event.findEvent(event.getId());
        event.setNote(note);
        event.setDateOfEvent(dateOfEvent);
        event.merge();
        

        event = Event.findEvent(event.getId());
        Score challengerScore = event.getChallengerScore();
        Score defenderScore = event.getDefenderScore();
        
        challengerScore.setScore(challengerScoreValue);
        defenderScore.setScore(defenderScoreValue);
        
        challengerScore.merge();
        defenderScore.merge();
        
        Challenge challenge = new Challenge();
        challenge.setEvent(event);
        challenge.setNote(event.getNote());
        challenge.persist();
        
        event = Event.findEvent(event.getId());
        challenge = Challenge.findChallenge(challenge.getId());
        event.addChallenge(challenge);
        
        this.getEventService().setWinner(event, challengerScoreValue, defenderScoreValue);  
        this.getNotificationService().notifyTeamMembersEventChanged(event);
        return "redirect:/event/" + event.getId();
    }

    @RequestMapping(value = "/event/{id}/form", method = RequestMethod.GET)
    public String updateForm(@PathVariable("id") Long id, ModelMap modelMap) {
        if (id == null) throw new IllegalArgumentException("An Identifier is required");
        Event event = Event.findEvent(id);
        modelMap.addAttribute("event", event);
        modelMap.addAttribute("event_dateOfEvent_date_format", org.joda.time.format.DateTimeFormat.patternForStyle("S-", org.springframework.context.i18n.LocaleContextHolder.getLocale()));
        return "event/update";
    }

	@PreAuthorize("hasRole('ROLE_ADMIN')")
    @RequestMapping(value = "/event/{id}", method = RequestMethod.DELETE)
    public String delete(@PathVariable("id") Long id, @RequestParam(value = "page", required = false) Integer page, @RequestParam(value = "size", required = false) Integer size) {
        if (id == null) throw new IllegalArgumentException("An Identifier is required");
        Event.findEvent(id).remove();
        return "redirect:/event?page=" + ((page == null) ? "1" : page.toString()) + "&size=" + ((size == null) ? "10" : size.toString());
    }
    
    @RequestMapping(value = "find/ByDateOfEventGreaterThanEquals/form", method = RequestMethod.GET)
    public String findEventsByDateOfEventGreaterThanEqualsForm(ModelMap modelMap) {
        modelMap.addAttribute("event_dateOfEvent_date_format", org.joda.time.format.DateTimeFormat.patternForStyle("S-", org.springframework.context.i18n.LocaleContextHolder.getLocale()));
        return "event/findEventsByDateOfEventGreaterThanEquals";
    }
    
    @RequestMapping(value = "find/ByDateOfEventGreaterThanEquals", method = RequestMethod.GET)
    public String findEventsByDateOfEventGreaterThanEquals(@RequestParam("dateOfEvent") @DateTimeFormat(style = "S-") Calendar dateOfEvent, ModelMap modelMap) {
        if (dateOfEvent == null) throw new IllegalArgumentException("A DateOfEvent is required.");
        modelMap.addAttribute("events", Event.findEventsByDateOfEventGreaterThanEquals(dateOfEvent).getResultList());
        modelMap.addAttribute("event_dateOfEvent_date_format", org.joda.time.format.DateTimeFormat.patternForStyle("S-", org.springframework.context.i18n.LocaleContextHolder.getLocale()));
        return "event/list";
    }
    
    @RequestMapping(value = "find/ByTournament/form", method = RequestMethod.GET)
    public String findEventsByTournamentForm(ModelMap modelMap) {
        modelMap.addAttribute("tournaments", Tournament.findAllTournaments());
        return "event/findEventsByTournament";
    }
    
    @RequestMapping(value = "find/ByTournament", method = RequestMethod.GET)
    public String findEventsByTournament(@RequestParam("tournament") Tournament tournament, ModelMap modelMap) {
        if (tournament == null) throw new IllegalArgumentException("A Tournament is required.");
        modelMap.addAttribute("events", Event.findEventsByTournament(tournament).getResultList());
        return "event/list";
    }
    
    @RequestMapping(value = "find/ByTournamentAndDateOfEventGreaterThanEquals/form", method = RequestMethod.GET)
    public String findEventsByTournamentAndDateOfEventGreaterThanEqualsForm(ModelMap modelMap) {
        modelMap.addAttribute("tournaments", Tournament.findAllTournaments());
        modelMap.addAttribute("event_dateOfEvent_date_format", org.joda.time.format.DateTimeFormat.patternForStyle("S-", org.springframework.context.i18n.LocaleContextHolder.getLocale()));
        return "event/findEventsByTournamentAndDateOfEventGreaterThanEquals";
    }
    
    @RequestMapping(value = "find/ByTournamentAndDateOfEventGreaterThanEquals", method = RequestMethod.GET)
    public String findEventsByTournamentAndDateOfEventGreaterThanEquals(@RequestParam("tournament") Tournament tournament, @RequestParam("dateOfEvent") @DateTimeFormat(style = "S-") Calendar dateOfEvent, ModelMap modelMap) {
        if (tournament == null) throw new IllegalArgumentException("A Tournament is required.");
        if (dateOfEvent == null) throw new IllegalArgumentException("A DateOfEvent is required.");
        modelMap.addAttribute("events", Event.findEventsByTournamentAndDateOfEventGreaterThanEquals(tournament, dateOfEvent).getResultList());
        modelMap.addAttribute("event_dateOfEvent_date_format", org.joda.time.format.DateTimeFormat.patternForStyle("S-", org.springframework.context.i18n.LocaleContextHolder.getLocale()));
        return "event/list";
    }
	private PermissionService permissionService;
	@Autowired
	public void setPermissionService(PermissionService permissionService) {
		this.permissionService = permissionService;
	}


	public PermissionService getPermissionService() {
		return permissionService;
	}
	private NotificationService notificationService;

	@Autowired
	public void setNotificationService(NotificationService notificationService) {
		this.notificationService = notificationService;
	}

	public NotificationService getNotificationService() {
		return notificationService;
	}
	
	private EventService eventService;
	@Autowired
	public void setEventService(EventService eventService){
		this.eventService = eventService;
	}
	public EventService getEventService(){
		return this.eventService;
	}
}
